module Project(
  input CLOCK_27,
  input CLOCK_50,
  input [3:0] KEY,
  input [17:0] SW,
  output [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, HEX6, HEX7,
  output reg [8:0] LEDG,	//  LED Green[8:0]
  output reg [17:0] LEDR,	//  LED Red[17:0]
  input	PS2_DAT,
  input PS2_CLK,
  output TD_RESET, // TV Decoder Reset
  inout I2C_SDAT,		// I2C Data
  output I2C_SCLK,		// I2C Clock
  output AUD_ADCLRCK,	// Audio CODEC ADC LR Clock
  input AUD_ADCDAT,		// Audio CODEC ADC Data
  output AUD_DACLRCK,	// Audio CODEC DAC LR Clock
  output AUD_DACDAT,	// Audio CODEC DAC Data
  inout AUD_BCLK,		// Audio CODEC Bit-Stream Clock
  output AUD_XCK,		// Audio CODEC Chip Clock
  inout  [35:0]  GPIO_0, GPIO_1
);
	assign  GPIO_0    =  36'hzzzzzzzzz;
	assign  GPIO_1    =  36'hzzzzzzzzz;

	wire reset = 1'b0;
	wire [7:0] scan_code;
	reg [7:0] current_key[0:1];
	wire read, scan_ready;
	
	wire DLY_RST;
	Reset_Delay r0(	.iCLK(CLOCK_50),.oRESET(DLY_RST) );

	oneshot pulser(
	   .pulse_out(read),
	   .trigger_in(scan_ready),
	   .clk(CLOCK_50)
	);

	keyboard kbd(
	  .keyboard_clk(PS2_CLK),
	  .keyboard_data(PS2_DAT),
	  .clock50(CLOCK_50),
	  .reset(reset),
	  .read(read),
	  .scan_ready(scan_ready),
	  .scan_code(scan_code)
	);
	
	assign TD_RESET = 1'b1;  // Enable 27 MHz
	
	VGA_Audio_PLL 	p1 (	
		.areset(~DLY_RST),
		.inclk0(CLOCK_27),
		.c0(VGA_CTRL_CLK),
		.c1(AUD_CTRL_CLK),
		.c2(VGA_CLK)
	);

	I2C_AV_Config u3(	
	//	Host Side
	  .iCLK(CLOCK_50),
	  .iRST_N(KEY[0]),
	//	I2C Side
	  .I2C_SCLK(I2C_SCLK),
	  .I2C_SDAT(I2C_SDAT)	
	);

	assign	AUD_ADCLRCK	=	AUD_DACLRCK;
	assign	AUD_XCK		=	AUD_CTRL_CLK;

	audio_clock u4(	
	//	Audio Side
	   .oAUD_BCK(AUD_BCLK),
	   .oAUD_LRCK(AUD_DACLRCK),
	//	Control Signals
	  .iCLK_18_4(AUD_CTRL_CLK),
	   .iRST_N(DLY_RST)	
	);

	audio_converter u5(
		// Audio side
		.AUD_BCK(AUD_BCLK),       // Audio bit clock
		.AUD_LRCK(AUD_DACLRCK), // left-right clock
		.AUD_ADCDAT(AUD_ADCDAT),
		.AUD_DATA(AUD_DACDAT),
		// Controller side
		.iRST_N(DLY_RST),  // reset
		.AUD_outL(audio_outL),
		.AUD_outR(audio_outR),
		.AUD_inL(audio_inL),
		.AUD_inR(audio_inR)
	);

	hex_7seg dsp0(current_key[0][3:0],HEX0);
	hex_7seg dsp1(current_key[0][7:4],HEX1);
	hex_7seg dsp2(current_key[1][3:0],HEX2);
	hex_7seg dsp3(current_key[1][7:4],HEX3);
	
	wire [3:0] track_selection = SW[3:0];
	reg [3:0] track_selected;
	reg recording = 0, playing = 0;
	reg [31:0] clock_counter = 0;
	reg [3:0] tempo_counter[0:31], playback_counter[0:31]; // 4 recording & playing counters
	reg [7:0] recording_buffer[0:3][0:479]; //4 recordings, 30 seconds each
	reg [4:0] number_of_tracks, recording_track;
	
	initial begin
		tempo_counter[0] = 0;
		tempo_counter[1] = 0;
		tempo_counter[2] = 0;
		tempo_counter[3] = 0;
	end
	
	always @(posedge scan_ready) begin
		current_key[1] <= current_key[0];
		current_key[0] <= scan_code;
	end
	
	function [31:0] keyboard_lookup;
		input [7:0] key;
		case(key)
			8'h1C: keyboard_lookup = 174; //a ~ F
			8'h1D: keyboard_lookup = 184; //w ~ F-sharp
			8'h1B: keyboard_lookup = 195; //s ~ G
			8'h24: keyboard_lookup = 207; //e ~ G-sharp
			8'h23: keyboard_lookup = 220; //d ~ A
			8'h2D: keyboard_lookup = 233; //r ~ A-sharp
			8'h2B: keyboard_lookup = 246; //f ~ B
			8'h34: keyboard_lookup = 261; //g ~ MIDDLE C
			8'h35: keyboard_lookup = 277; //y ~ C-sharp
			8'h33: keyboard_lookup = 293; //h ~ D
			8'h3C: keyboard_lookup = 311; //u ~ D-sharp
			8'h3B: keyboard_lookup = 329; //j ~ E
			8'h42: keyboard_lookup = 349; //k ~ F
			8'h44: keyboard_lookup = 369; //o ~ F-sharp
			8'h4B: keyboard_lookup = 391; //l ~ G
			8'h4D: keyboard_lookup = 415; //p ~ G-sharp
			default: keyboard_lookup = 0;
		endcase
	endfunction
	
	//http://www.edaboard.com/thread177879.html
	function [31:0] clogb2;
		input [31:0] value;
		integer i;
		begin
			clogb2 = 0;
			for(i = 0; 2**i < value; i = i + 1)
				clogb2 = i + 1;
		end
	endfunction
	
	reg [31:0] freq;
	wire [31:0] dds_incr;
	reg [31:0] i; // for the for loop
	always @(posedge CLOCK_50) begin
		if (current_key[1] != 8'hF0) begin
			if (current_key[0] == 5 && !playing && !recording) begin
				if ((^ track_selection)) begin //Check only 1 track select
					track_selected = track_selection;
					recording = 1;
					recording_track = clogb2(track_selected);
					tempo_counter[recording_track] = 0;
				end
			end else if (current_key[0] == 6 && !playing && recording) begin
				recording = 0;
			end else if (current_key[0] == 4 && !recording && !playing) begin
				if ((| track_selection)) begin //Any track selected
					track_selected = track_selection;
					playing = 1;
					for (i = 0; i < 4; i = i + 1) begin
						playback_counter[i] = 0;
					end
				end
			end else if (current_key[0] == 12 && !recording && playing) begin
				playing = 0;
				for (i = 0; i < 4; i = i + 1) begin
					playback_counter[i] = 0;
				end
			end
		end
	
		clock_counter = clock_counter + 1;
		if (clock_counter >= 1562500) begin
			if (recording) begin
				if (current_key[1] != 8'hF0) begin
					recording_buffer[recording_track][tempo_counter[recording_track]] = current_key[0];
				end else
					recording_buffer[recording_track][tempo_counter[recording_track]] = current_key[1];
				
				freq = keyboard_lookup(recording_buffer[recording_track][tempo_counter[recording_track]]);

				tempo_counter[recording_track] = tempo_counter[recording_track] + 1;
				if (tempo_counter[recording_track] > 479)
					recording = 0;
			end
			if (playing) begin
				freq = 0;
				number_of_tracks = 0;
				for (i = 0; i < 4; i = i + 1) begin
					if (playback_counter[i] <= tempo_counter[i]) begin
						number_of_tracks = number_of_tracks + 1;

						freq = freq + keyboard_lookup(recording_buffer[i][playback_counter[i]]);

						playback_counter[i] = playback_counter[i] + 1;
					end
				end
				if (number_of_tracks <= 0)
					playing = 0;
				else begin
					freq = freq / number_of_tracks;
				end
			end
			clock_counter = 0;
		end
		LEDG[0] = recording;
		LEDG[1] = playing;
		LEDR[3:0] = track_selected;
	end

	wire [15:0] audio_inL, audio_inR;
	wire [15:0] audio_outL, audio_outR;
	wire [15:0] signal;
	//set up DDS frequency
	reg [31:0] dds_phase;
	assign dds_incr = freq * 91626 ; //91626 = 2^32/46875 so freq is in Hz

	always @(negedge AUD_DACLRCK or negedge DLY_RST)
		if (!DLY_RST) dds_phase <= 0;
		else dds_phase <= dds_phase + dds_incr;

	wire [7:0] index = dds_phase[31:24];

	sine_table sig1(
		.index(index),
		.signal(audio_outR)
	);
endmodule
